<?php
/**
* php5 version for class databean.
* code and doc has to be updated from php4
* This file belongs to a webappkit package (kit)
* @link http://webappkit.net
* @package databeans
* @author J.Ducastel <jeremie@ducastel.name>
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/


/**
* "databean" php implementation
* stores, checks and formats data as members
* searches for member-related methods for setting, getting, checking, input and output filtering etc of members
* bool _{member}_check($x)
* mixed _{member}_get($x)
* mixed _{member}_set($x)
* bool _{member}_gettable($x)
* bool _{member}_settable($x)
* mixed _{member}_inputfilter($x)
* mixed _{member}_outputfilter($x)
* mixed _{member}_autovalue()
* @author J.Ducastel <jeremie@ducastel.name>
*/
class dataBean {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
	/**
	* constructor for php4
	* @access
	*/
	function dataBean($data=NULL) {
		$this->__construct($data);
	}/**/
	
	/**
	* "real" constructor
	* @access public
	*/
	public function __construct($data=NULL) {
		// setting provided values or autovalues
		
		// setting auto values
		$this->autoValues();
		// setting members'values if valid
		if (is_array($data))
			$this->loadMembers($data);
		// setting locks if required
		/*if ($this->_databean_lock_structure_afterbuilt)
			$this->_databean_lock_structure=true;
		if ($this->_databean_lock_members_afterbuilt)
			$this->_databean_lock_members=true;*/
	}/**/
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
	/**
	* locks / unlocks databean data, provide lock status
	* @access public
	* @param bool $newstate optional, new lock state
	* @return bool
	*/
	public function membersLock($newstate=null) {
		if (is_bool($newstate))
			$this->_databean_lock_members=$newstate;
		return $this->_databean_lock_members;
	}/**/
	
	/**
	* locks / unlocks databean structure, provide lock status
	* properties can't be set if not declared first
	* @access public
	* @param bool $newstate optional, new lock state
	* @return bool
	*/
	public function structureLock($newstate=null) {
		if (is_bool($newstate))
			$this->_databean_lock_structure=$newstate;
		return $this->_databean_lock_structure;
	}/**/
	
	/**
	* enable/disable inputfilters, provide inputfilters status
	* @access public
	* @param bool $newstate optional
	* @return bool
	*/
	public function inputFilters($newstate=null) {
		if (is_bool($newstate))
			$this->_databean_inputfilters=$newstate;
		return $this->_databean_inputfilters;
	}/**/
	
	/**
	* enable/disable outputfilters, provide outputfilters status
	* @access public
	* @param bool $newstate optional
	* @return bool
	*/
	public function outputFilters($newstate=null) {
		if (is_bool($newstate))
			$this->_databean_outputfilters=$newstate;
		return $this->_databean_outputfilters;
	}/**/
	
	/**
	* enable/disable check before setting members
	* @access public
	* @param bool $newstate optional
	* @return bool
	*/
	public function checkOnSet($newstate=null) {
		if (is_bool($newstate))
			$this->_databean_checkonset=$newstate;
		return $this->_databean_checkonset;
	}/**/
	
	/**
	* tries to load an array as properties
	* @access public
	* @param array $data
	* @return int number of successfully loaded properties
	*/
	public function loadMembers(& $data) {
		$loaded=0;
		if ($this->membersLock() or !is_array($data))
			return 0;
		foreach (array_keys($data) as $key) {
			if ($this->setMember($key,$data[$key])) $loaded++;
		}
		return $loaded;
	}/**/
	/**
	* alias for loadmembers
	*/
	public function loadData(& $data) {
		return $this->loadMembers($data);
	}/**/
	
	/**
	* return a member's value
	* @param string $key
	* @access public
	* @return mixed
	*/
	public function getMember($key) {
		// checking get is allowed
		if (!$this->memberGettable($key)) {
			trigger_error("databean->get() not allowed for $key");
			return null;
		}
		// searching for custom method
		$method='_'.$key.'}_get';
		if (method_exists($this,$method)) {
			return $this->$method();
		}
		// getting member's value
		$value=isset($this->$key)?$this->$key:null;
		// output filtering
		return $this->memberOutputFilter($key,$value);
	}/**/
	/**
	* alias for getMember
	*/
	public function get($key) {
		return $this->getMember($key);
	}/**/
	public function __get($key) {
		return $this->getMember($key);
	}
	
	/**
	* indicates wether member is gettable
	* @access public
	* @param string $key
	* @return bool
	*/
	public function memberGettable($key) {
		// searching for member's custom method
		$method='_'.$key.'_gettable';
		if (method_exists($this,$method)) {
			return $this->$method();
		}
		return true;
	}/**/
	
	/**
	* getall members as associative array
	* @access public
	* @return array
	*/
	public function & getAllAssoc() {
		$assoc=array();
		$keys=$this->_databean_getMembers();
		foreach ($keys as $key)
			$assoc[$key]=$this->getMember($key);
		return $assoc;
	}/**/
	/**
	* alias for getallassoc
	*/
	public function & getAll() {
		$assoc=&$this->getAllAssoc();
		return $assoc;
	}
	
	/**
	* set databean property's value, if checks are ok
	* @param string $key
	* @param mixed $value
	* @access public
	* @return bool
	*/
	public function setMember($key,$value) {
		// checking databean lock
		if ($this->membersLock()) {
			trigger_error("databean->set(): databean is locked");
			return false;
		}
		// checking set allowed
		if (!$this->memberSettable($key)) {
			trigger_error("databean->set() not allowed for $key");
			return false;
		}
		// searching for custom method
		$method='_'.$key.'_set';
		if (method_exists($this,$method)) {
			return $this->$method($value);
		}
		// applying input filter
		if ($this->inputFilters()) {
			$value=&$this->memberInputFilter($key,$value);
		}
		// checking validity
		if (!$this->checkMember($key,$value)) {
			trigger_error(get_class($this)."->setMember($key,$value) : value doesn't pass check");
			return false;
		}
		// finally setting value
		$this->$key=$value;
		return true;
	}/**/
	public function set($key,$value) {
		return $this->setMember($key,$value);
	}/**/
	public function __set($key,$value) {
		return $this->setMember($key,$value);
	}
	
	/**
	* indicates wether set is allowed for member
	* @access public
	* @param string $key member's name
	* @return bool
	*/
	public function memberSettable($key) {
		// searching for member's custom method
		$method='_'.$key.'_settable';
		if (method_exists($this,$method)) {
			return $this->$method();
		}
		// disallow if structure is locked and is not declared property
		if ($this->structureLock()) {
			$properties=$this->_databean_getMembers();
			if (!in_array($key,$properties)) {
				trigger_error($key.' is not a member of '.get_class($this).' and structure is locked');
				return false;
			}
		}
		return true;
	}/**/
	
	/**
	* search for member's input filter and applies it to return value
	* or return value 
	* @access public
	* @param string $key
	* @param mixed $value
	*/
	public function & memberInputFilter($key,$value) {
		$this->_databean_callCustomMethod("_{$key}_inputfilter",$value);
		return $value;
	}/**/
	
	/**
	* search for member's input filter and applies it on value
	* or return value 
	* @access public
	* @param string $key
	* @param mixed $value
	*/
	public function & memberOutputFilter($key,$value) {
		$this->_databean_callCustomMethod("_{$key}_outputfilter",$value);
		return $value;
	}/**/
	
	/**
	* checks a value for a property.
	* if no value provided, checks current property's value
	* @access public
	* @param string $key
	* @param mixed $value optional
	* @return bool
	*/
	public function checkMember($key, $value=NULL) {
		// getting current value if omitted
		if (is_null($value) and isset($this->$key))
			$value=$this->$key;
		// checks value
		// custom checking methods
		$method="_{$key}_check";
		if (method_exists($this,$method)) {
			return $this->$method($value);
		}
		// no check defined
		return true;
	}/**/
	
	/**
	* checks bean global validity
	* by default, only checks each required member
	* @access public
	* @return bool
	*/
	public function globalCheck() {
		return $this->_databean_checkRequiredMembers();
	}/**/
	/**
	* checks global or member's validity
	*/
	public function isValid($member=null) {
		if (is_null($member))
			return $this->globalCheck();
		else
			return $this->checkMember($member);
	}/**/
	
	/**
	* assign automatic values for fields
	* searches for _{member}_autovalue methods
	* (then _{member}_autovalue properties) removed
	*/
	public function autoValues() {
		$members=$this->_databean_getMembers();
		foreach ($members as $key) {
			$method="_{$key}_autovalue";
			$property=$method;
			if (method_exists($this,$method)) {
				$this->$key=$this->$method();
			}/* else if (isset($this->$property)) {
				$this->$key=$this->$property;
			}*/
		}
		return true;
	}/**/

	

/*------------------------------------------------------------------------------
                                                                      properties
------------------------------------------------------------------------------*/
	/**
	* @var bool enable/disable set() and loadData()
	*/
	protected $_databean_lock_members=false;
	/**
	* @var bool enable/disable setting undeclared members
	*/
	protected $_databean_lock_structure=true;
	/**
	* @var bool enable/disable input filter methods on setMember()
	*/
	protected $_databean_inputfilters=true;
	/**
	* @var bool enable/disable output filter methods on getMember()
	*/
	protected $_databean_outputfilters=true;
	/**
	* @var bool if true, check member's validity before setting and don't set if invalid
	*/
	protected $_databean_checkonset=true;
	/**
	* @var bool enable structure lock
	* properties can't be set if not declared first
	*/
	//var $_databean_lock_structure=false;
	
	/**
	* @var bool sets _databean_lock_data=true after building
	*/
	//var $_databean_lock_members_afterbuilt=false;
	/**
	* @var bool sets _databean_lock_structure=true after building
	*/
	//var $_databean_lock_structure_afterbuilt=false;
	
/*------------------------------------------------------------------------------
                                                               protected methods
------------------------------------------------------------------------------*/
	
	/**
	* return bean's declared properties
	* i.e. all vars not starting by an underscore
	* @access protected
	* @return array
	*/
	protected function & _databean_getMembers() {
		// getting all instance vars
		$class=get_class($this);
		$allvars=array_keys(get_class_vars($class));
		$members=array();
		foreach ($allvars as $var) {
			if (substr($var,0,1)!='_')
				$members[]=$var;
		}
		return $members;
	}/**/
	protected function _getMembers() {
		return $this->_databean_getMembers();
	}
	
	/**
	* Checks validity for all members flagged as required
	* @access protected
	* @return bool
	*/
	protected function _databean_checkRequiredMembers() {
		$members=$this->_databean_getMembers();
		foreach ($members as $key) {
			$method='_'.$key.'_required';
			if (method_exists($this,$method) and $this->$method() and !$this->checkMember($key))
				return false;
		}
		return true;
	}/**/
	protected function _checkRequiredMembers() {
		return $this->_databean_checkRequiredMembers();
	}
	
	/**
	* calls custom own method on value
	* @param string $method
	* @param mixed &$value
	* @access protected
	* @return bool
	*/
	protected function _databean_callCustomMethod($method,&$value) {
		if (!method_exists($this,$method))
			return false;
		$value=$this->$method($value);
		return true;
	}/**/
	
	/**
	* 
	* @param
	* @access protected
	* @return 
	* /
	function () {
		
	}/**/
/*------------------------------------------------------------------------------
                                                                 private methods
------------------------------------------------------------------------------*/
	/**
	* 
	* @param
	* @access private
	* @return 
	* /
	function () {
		
	}/**/
}
?>
